<?php

/**
 * Класс предназнает для общения непосредственно с API Вконтакте.
 * Запросы и ответы, обрабатываемые этим классом логируются для упрощения поиска возможных и невозможных ошибок.
 */
class VkClient extends Zend_Http_Client implements ISingleton
{
	/**
	 * @var VkClient
	 */
	private static $_instance;	

	/**
	 * @return VkClient
	 */
	public static function getInstance()
	{
		if (!self::$_instance) {
			self::$_instance = new self();
		}
	
		return self::$_instance;
	}
	
	/**
	 * Упрощенный интерфейс посылки запросов к API Вконтакте.
	 * Самостоятельно формирует URL, добавляет к запросу токен, обрабатывает ошибки,
	 * производит логирование
	 * 
	 * @param string $method
	 * @param array $params
	 * @return array
	 * @throws Zend_Service_Exception
	 */
	public function api($method, $params = array())
	{
		// Если в запросе нет access_token, пытаемся взять его у текущего авторизованного пользователя
		if (!isset($params['access_token'])) {
			$user = Auth::getInstance()->getProfile();
			if ($user && $user->getAccessToken()) {
				$params['access_token'] = $user->getAccessToken();
			}
		}
		
		$pice = array();
		foreach ($params as $k => $v) {
			$pice[] = $k . '=' . urlencode($v);
		}
		
		$params = implode('&', $pice);
		
		$url = 'https://api.vk.com/method/' . $method . '?' . $params;
		$this->setUri($url);
		$response = $this->request('GET');
		$json = json_decode($response->getBody(), true);
		return $json;
	}

	/**
	 * Посылает HTTP запрос к API Вконтакте и логирует сам запрос и ответ в БД и внутри класса.
	 * Send the HTTP request and return an HTTP response object.
	 *
	 * @param string $method
	 * @return Zend_Http_Response
	 * @throws Zend_Http_Client_Exception
	 * @throws VkException
	 */
	public function request($method = null)
	{
		$log = VkApiLogPeer::getInstance()->createRow();
		
		$user = Auth::getInstance()->getProfile();
		if ($user) {
			$log->setUserId($user->getId());
		}
		
		$log->setUrl($this->getUri()->getUri());
		
		try {
			$time = time();
			$response = parent::request($method);
			$time = time() - $time;
			$log->setDelay($time);
		} catch (Zend_Http_Client_Exception $e) {
			$log->setError($e->getMessage());
			$log->setIsError(1);
			$log->save();
			throw $e;
		}
		
		$log->setHttpRequest($this->getLastRequest());
		$log->setHttpResponse($response->getHeadersAsString() . "\n" . $response->getBody());
		
		$json = json_decode($response->getBody(), true);
		if (isset($json['error'])) {
			$error = $json['error'];
			$errorInfo = array();
			
			if (isset($error['request_params'])) {
				foreach ($error['request_params'] as $p) {
					if ($p['key'] == 'method') {
						$errorInfo['METHOD'] = $p['value'];
						break;
					}
				}
			}
			
			if (isset($error['error_code'])) {
				$errorInfo['CODE'] = $error['error_code'];
			}
				
			if (isset($error['error_msg'])) {
				$errorInfo['MSG'] =  mb_convert_encoding($error['error_msg'], 'utf-8', 'windows-1251');
			}

			if (isset($error['error_description'])) {
				$errorInfo['DESCR'] = mb_convert_encoding($error['error_description'], 'utf-8', 'windows-1251');
			}
			
			$errorMessage = "";
			$i = 0;
			foreach ($errorInfo as $key => $value) {
				$errorMessage .= "$key: $value";
				
				$i++;
				if (count($errorInfo) != $i) {
					$errorMessage .= ", ";
				}
			}
			
			$log->setIsError(1);
			$log->setError($errorMessage);
			$log->save();
			
			$errorMessage .= " LOG_ID: " . $log->getId();
			throw new VkException($errorMessage);
		}
		
		$log->save();
		return $response;
	}
	
	/**
	 * Возвращает URL по которому надо авторизовать пользователя.
	 * 
	 * @link http://vk.com/developers.php?oid=-1&p=%D0%90%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2
	 * @return string
	 */
	public function getAuthUrl()
	{
		$host = $_SERVER['HTTP_HOST'];
		$returnUrl = "http://$host/auth/";
		$appId = Config::getInstance()->vk->app_id;
		$url = "http://api.vk.com/oauth/authorize?client_id=$appId&scope=wall&redirect_uri=$returnUrl&response_type=code";
		return $url;
	}
	
	/**
	 * Возвращает URL, по которому сервер может получить токен пользователя.
	 * 
	 * @link http://vk.com/developers.php?oid=-1&p=%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BA%D0%BB%D1%8E%D1%87%D0%B0_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%B0
	 * @param string $code
	 * @return string
	 */
	public function getAccessTokenByCodeUrl($code)
	{
		$appId = Config::getInstance()->vk->app_id;
		$secret = Config::getInstance()->vk->app_secret;
		
		$uri = "https://api.vk.com/oauth/access_token?client_id=$appId&client_secret=$secret&code=$code";
		return $uri;
	}
}